/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package ca.uwo.android.rss.events;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import android.util.Log;
import android.util.Xml;

/**
 * This class parses XML feeds from stackoverflow.com.
 * Given an InputStream representation of a feed, it returns a List of entries,
 * where each list element represents a single entry (post) in the XML feed.
 */
public class StackOverflowXmlParser {
	private final String ns = null;
	private final String RDF_NAMESPACE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
	private final String EV_NAMESPACE = "http://purl.org/rss/1.0/modules/event/";
	private final String DC_NAMESPACE = "http://purl.org/dc/elements/1.1/";
	
    private int urlType;
    private String table;
    private EventsDataSource datasource;
    
    public List<RssEvent> parse(InputStream in, int urlType, EventsDataSource datasource) throws XmlPullParserException, IOException {
       
    	this.urlType = urlType;            
    	this.datasource = datasource; 
    	
    	try {
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            factory.setNamespaceAware(true);
            XmlPullParser parser = factory.newPullParser(); 
            parser.setInput(in, null);
            
            parser.nextTag();  // for alumni event, bug parsing special character e.g. &hellip, character encoding issue
            Log.i("ALUMNI", "Bug not reached yet");
            
            return readFeed(parser);
        } finally {
            in.close();
        }
    }

    private List<RssEvent> readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
      
    	List<RssEvent> entries = new ArrayList<RssEvent>();
        
        String name = parser.getName();
        String prefix = parser.getPrefix();
       
        if ( prefix != null && prefix.equals("rdf") && name.equals("RDF") ){ // non alumni + mustangs events
        		parser.require(XmlPullParser.START_TAG, RDF_NAMESPACE, "RDF");
        }
        else{ // alumni or mustangs events
            Log.i("" + urlType, "TEST2");
        	parser.require(XmlPullParser.START_TAG, ns, "rss");
        	parser.nextTag();
        }
       
        
        while (parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
            name = parser.getName();
            // Starts by looking for the entry tag
            if (name.equals("item")) {
                entries.add(readEntry(parser));
                
            } else {
                skip(parser);
            }
        }
       
        
        return entries;
    }

    // Parses the contents of an entry. If it encounters a title, summary, or link tag, hands them
    // off
    // to their respective &quot;read&quot; methods for processing. Otherwise, skips the tag.
    private RssEvent readEntry(XmlPullParser parser) throws XmlPullParserException, IOException {
    	String title = "", description = "", link = "", date = "";
    	RssEvent entry = new RssEvent();
    	
    	parser.require(XmlPullParser.START_TAG, ns, "item");
        
        while (parser.next() != XmlPullParser.END_TAG) {
            
        	if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
         
        	String name = parser.getName();
            String prefix = parser.getPrefix();
            
            if (name.equals("title")) {
            	title = readTitle(parser);
                entry.setTitle(title);
            } else if (name.equals("description")) {
            	description = readSummary(parser);
				
            	if (description.indexOf("<img src") != -1) {
					// removes <img src=""> tags from description (for mustangs events
            		description = description.replaceAll("\\x3Cimg src{1}.*\\x2F\\x3E", "");
				}
            	
            	entry.setDescription(description);
            } else if (name.equals("link")) {
            	link = readLink(parser);
                entry.setLink(link);
            } else if (name.equals("pubDate")) { // alumni event dates
                parser.require(XmlPullParser.START_TAG, ns, "pubDate");
                date = readText(parser);					
                parser.require(XmlPullParser.END_TAG, ns, "pubDate");
                entry.setDate(date);
            } else if (prefix != null && prefix.equals("ev") && name.equals("startdate")) { // mustangs event dates
                parser.require(XmlPullParser.START_TAG, EV_NAMESPACE, "startdate");
                date = readText(parser);
                parser.require(XmlPullParser.END_TAG, EV_NAMESPACE, "startdate");
                
				if (date != null)
					date = date.substring(0, date.indexOf("T"));
                
                entry.setDate(date);
            } else if (prefix != null && prefix.equals("dc") && name.equals("date")) { // all other event dates?
                parser.require(XmlPullParser.START_TAG, DC_NAMESPACE, "date");
                date = readText(parser);
                parser.require(XmlPullParser.END_TAG, DC_NAMESPACE , "date");
                entry.setDate(date);	
            	
            } else {
                skip(parser);
            }
        }
     
     /* Log.i("FEED", "URLTYPE: " + urlType + 
    		        "\nTITLE: " + title + 
    		        "\nDESCRIPTION: " + description + 
    		        "\nLINK: " + link + 
    		        "\nDATE: " + entry.getDate() + "\n");*/
  //      datasource.createEvent(urlType, title, description, link, "DATE PARSING TO BE IMPLEMENTED");
        
        return entry;
    }

    // Processes title tags in the feed.
    private String readTitle(XmlPullParser parser) throws IOException, XmlPullParserException {
        parser.require(XmlPullParser.START_TAG, ns, "title");
        String title = readText(parser);
        parser.require(XmlPullParser.END_TAG, ns, "title");
        return title;
    }

    // Processes link tags in the feed.
    private String readLink(XmlPullParser parser) throws IOException, XmlPullParserException {
        //String link = "";
        parser.require(XmlPullParser.START_TAG, ns, "link");
        String link = readText(parser);
        //String tag = parser.getName();
/*        String relType = parser.getAttributeValue(null, "rel");
        if (tag.equals("link")) {
            if (relType.equals("alternate")) {
                link = parser.getAttributeValue(null, "href");
                parser.nextTag();
            }
        }*/
        parser.require(XmlPullParser.END_TAG, ns, "link");
        return link;
    }

    // Processes summary tags in the feed.
    private String readSummary(XmlPullParser parser) throws IOException, XmlPullParserException {
        parser.require(XmlPullParser.START_TAG, ns, "description");
        String description = readText(parser);
        parser.require(XmlPullParser.END_TAG, ns, "description");
        return description;
    }

    // For the tags title and summary, extracts their text values.
    private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
        String result = "";
        if (parser.next() == XmlPullParser.TEXT) {
            result = parser.getText();
            parser.nextTag();
        }
        return result;
    }
    

    // Skips tags the parser isn't interested in. Uses depth to handle nested tags. i.e.,
    // if the next tag after a START_TAG isn't a matching END_TAG, it keeps going until it
    // finds the matching END_TAG (as indicated by the value of "depth" being 0).
    private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
        if (parser.getEventType() != XmlPullParser.START_TAG) {
            throw new IllegalStateException();
        }
        int depth = 1;
        while (depth != 0) {
            switch (parser.next()) {
            case XmlPullParser.END_TAG:
                    depth--;
                    break;
            case XmlPullParser.START_TAG:
                    depth++;
                    break;
            }
        }
    }
}
